package graphic.window;

import ppa1.DrawingTool;

/**
 * This class functions as wrapper above the DrawingTool library.
 * 
 * The main purpose of this was to implement 2D rotation without manually managing
 * calculations in all drawing parts.
 * 
 * @author Tomas Zima
 */
public class GraphicContextWindow extends DrawingTool
{
	/**
	 * Constructor.
	 * 
	 * Pass all arguments to original DrawingTool constructor via super() method.
	 * Also, this initialize some wrapper's attributes.
	 * 
	 * @param int [width]
	 *		width of the window
	 * 
	 * @param int [height]
	 *		height of the window
	 */
	public GraphicContextWindow(int width, int height)
	{
		// Call previous constructor
		super(width, height, true);
		
		// Save informations about window size
		this.width			= width;
		this.height			= height;
		
		// Enable wrapper functionality
		this.wrapperState	= true;
		
		// Default state: no rotation
		this.rotationDeg		= 0.0f;
	}

	/**
	 * Returns width of the window.
	 * 
	 * @param void
	 * @return int
	 */
	@Override
	public int getWidth()
	{
		return width;
	}
	
	/**
	 * Returns height of the window.
	 * 
	 * @param void
	 * @return int
	 */
	@Override
	public int getHeight()
	{
		return height;
	}
	
	/**
	 * Enables wrapper functionality. This means, that some overloaded methods will
	 * act differently (extended functionality).
	 * 
	 * @param void
	 * @return void
	 */
	public void enableWrapper()
	{
		this.wrapperState = true;
	}
	
	/**
	 * Disable wrapper functionality. This means, that every overloaded method will
	 * act just like normal, when using raw DrawingTool.
	 * 
	 * @param void
	 * @return void
	 */
	public void disableWrapper()
	{
		this.wrapperState = false;
	}
	
	/**
	 * Returns current state of the wrapper. True when enabled, false when disabled.
	 * 
	 * 
	 * @param void
	 * @return boolean
	 */
	public boolean isWrapperEnabled()
	{
		return this.wrapperState;
	}
	
	/**
	 * Sets angle of rotation.
	 * 
	 * @param float [angle]
	 *		angle of rotation in degrees
	 * @return void
	 */
	public void setRotationAngle(float angle)
	{
		this.rotationDeg = angle;
		this.rotationRad = Math.toRadians(angle);
	}
	
	/**
	 * Returns current rotation angle in degrees.
	 *
	 * @param void
	 * @return float
	 */
	public float getRotationAngle()
	{
		return this.rotationDeg;
	}
	
	/**
	 * Draws line between points [x1; y1] and [x2; y2]. If wrapper functionality
	 * is enabled, it calculates with rotation.
	 * 
	 * @param int [x1]
	 * @param int [y1]
	 * @param int [x2]
	 * @param int [y2]
	 * @return void
	 */
	@Override
	public void line(int x1, int y1, int x2, int y2)
	{
		if (wrapperState == false)
		{
			super.line(x1, y1, x2, y2);
		}
		else
		{
			int A[] = calculateRotation(x1, y1);
			int B[] = calculateRotation(x2, y2);
			
			super.line(A[0], A[1], B[0], B[1]);
		}
	}
	
	/**
	 * Calculate 2D rotation for one point (P => P', respectively [x; y] => [x'; y']).
	 * 
	 * @param int [x]
	 *		Coordinate in X axis.
	 * 
	 * @param int [y]
	 *		Coordinate in Y axis.
	 * 
	 * @return int[]
	 *		- index 0: x'
	 *		- index 1: y'
	 */
	protected int[] calculateRotation(int x, int y)
	{
		// Array for store result (two coordinates)
		int result[] = new int[2];

		x -= rotationCenterX;
		y -= rotationCenterY;
		
		// Calculate rotation
		result[0] = (int) (x * Math.cos(rotationRad) - y * Math.sin(rotationRad));
		result[1] = (int) (x * Math.sin(rotationRad) + y * Math.cos(rotationRad));
		
		result[0] += rotationCenterX;
		result[1] += rotationCenterY;
		
		// Return coordinations of rotated point
		return result;
	}

	public void setRotationCenter(int x, int y)
	{
		this.rotationCenterX = x;
		this.rotationCenterY = y;
	}
	
	public int getRotationCenterX()
	{
		return rotationCenterX;
	}
	
	public int getRotationCenterY()
	{
		return rotationCenterY;
	}
	
	private int			width;				// Window's width
	private int			height;				// Window's height
	
	private boolean		wrapperState;		// State of the wrapper
	
	private float		rotationDeg;		// Current rotation (angle in degrees)
	private double		rotationRad;		// Current rotation (angle in radians)
	
	private int			rotationCenterX = 0;
	private int			rotationCenterY = 0;
}
